
#include "DSInterface.h"
#include "..\\Stack\\src\\ArrayStack.h"
#include "..\\Stack\\src\\ConcurrentArrayStack.h"
#include "..\\Stack\\src\\LinkedStack.h"
#include "..\\Stack\\src\\ConcurrentLinkedStack.h"
#include "..\\Queue\\src\\ArrayQueue.h"
#include "..\\Queue\\src\\ConcurrentArrayQueue.h"
#include "..\\Queue\\src\\LinkedQueue.h"
#include "..\\Queue\\src\\ConcurrentLinkedQueue.h"

BaseStack<int>* bindIntStack(DSHandle* a_hDS);
BaseQueue<int>* bindIntQueue(DSHandle* a_hDS);

void invokeDS(DSHandle* handle);
void invokeArrayStack(DSHandle* handle);
void invokeConcurrentArrayStack(DSHandle* handle);
void invokeLinkedStack(DSHandle* handle);
void invokeConcurrentLinkedStack(DSHandle* handle);
void invokeArrayQueue(DSHandle* handle);
void invokeConcurrentArrayQueue(DSHandle* handle);
void invokeLinkedQueue(DSHandle* handle);
void invokeConcurrentLinkedQueue(DSHandle* handle);

void deleteDS(DSHandle* handle);
void deleteArrayStack(DSHandle* handle);
void deleteConcurrentArrayStack(DSHandle* handle);
void deleteLinkedStack(DSHandle* handle);
void deleteConcurrentLinkedStack(DSHandle* handle);
void deleteArrayQueue(DSHandle* handle);
void deleteConcurrentArrayQueue(DSHandle* handle);
void deleteLinkedQueue(DSHandle* handle);
void deleteConcurrentLinkedQueue(DSHandle* handle);

/////////////////////////////////////////////////////////////
//COMMON
/////////////////////////////////////////////////////////////
bool createDS(DSHandle* handle) {
	invokeDS(handle);
	return handle->bValid;
}

bool destroyDS(DSHandle* handle) {
	deleteDS(handle);
	return !handle->bValid;
}

void invokeDS(DSHandle* handle) {

	switch(handle->eDSType) {
		case eDSTYPE_ARRAY_STACK :
			invokeArrayStack(handle);
		break;
		case eDSTYPE_CONCURRENT_ARRAY_STACK :
			invokeConcurrentArrayStack(handle);
		break;
		case eDSTYPE_LINKED_STACK :
			invokeLinkedStack(handle);
		break;
		case eDSTYPE_CONCURRENT_LINKED_STACK :
			invokeConcurrentLinkedStack(handle);
		break;
		case eDSTYPE_ARRAY_QUEUE :
			invokeArrayQueue(handle);
		break;
		case eDSTYPE_CONCURRENT_ARRAY_QUEUE :
			invokeConcurrentArrayQueue(handle);
		break;
		case eDSTYPE_LINKED_QUEUE :
			invokeLinkedQueue(handle);
		break;
		case eDSTYPE_CONCURRENT_LINKED_QUEUE :
			invokeConcurrentLinkedQueue(handle);
		break;
		default :
			//no op.
		break;
	}
}

void deleteDS(DSHandle* handle) {

	switch(handle->eDSType) {
		case eDSTYPE_ARRAY_STACK :
			deleteArrayStack(handle);
		break;
		case eDSTYPE_CONCURRENT_ARRAY_STACK :
			deleteConcurrentArrayStack(handle);
		break;
		case eDSTYPE_LINKED_STACK :
			deleteLinkedStack(handle);
		break;
		case eDSTYPE_CONCURRENT_LINKED_STACK :
			deleteConcurrentLinkedStack(handle);
		break;
		case eDSTYPE_ARRAY_QUEUE :
			deleteArrayQueue(handle);
		break;
		case eDSTYPE_CONCURRENT_ARRAY_QUEUE :
			deleteConcurrentArrayQueue(handle);
		break;
		case eDSTYPE_LINKED_QUEUE :
			deleteLinkedQueue(handle);
		break;
		case eDSTYPE_CONCURRENT_LINKED_QUEUE :
			deleteConcurrentLinkedQueue(handle);
		break;
		default :
			//no op.
		break;
	}
}

void invokeArrayStack(DSHandle* handle) {

	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayStack<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayStack<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayStack<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void invokeConcurrentArrayStack(DSHandle* handle) {

	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayStack<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayStack<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayStack<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void invokeLinkedStack(DSHandle* handle) {

	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedStack<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedStack<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedStack<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void invokeConcurrentLinkedStack(DSHandle* handle) {

	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedStack<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedStack<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedStack<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void invokeArrayQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayQueue<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayQueue<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ArrayQueue<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void invokeConcurrentArrayQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayQueue<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayQueue<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentArrayQueue<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void invokeLinkedQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedQueue<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedQueue<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new LinkedQueue<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void invokeConcurrentLinkedQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedQueue<int>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_LONG :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedQueue<long>(handle->nMaxSize));
		}
		break;
		case eDATATYPE_PTR :
		{
			handle->ptrBinder = (UINT_PTR)(new ConcurrentLinkedQueue<UINT_PTR>(handle->nMaxSize));
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void deleteArrayStack(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			ArrayStack<int>* intArrayStack = (ArrayStack<int>*)handle->ptrBinder;
			delete intArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			ArrayStack<long>* longArrayStack = (ArrayStack<long>*)handle->ptrBinder;
			delete longArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			ArrayStack<UINT_PTR>* ptrArrayStack = (ArrayStack<UINT_PTR>*)handle->ptrBinder;
			delete ptrArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void deleteConcurrentArrayStack(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			ArrayStack<int>* intArrayStack = (ConcurrentArrayStack<int>*)handle->ptrBinder;
			delete intArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			ArrayStack<long>* longArrayStack = (ConcurrentArrayStack<long>*)handle->ptrBinder;
			delete longArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			ArrayStack<UINT_PTR>* ptrArrayStack = (ConcurrentArrayStack<UINT_PTR>*)handle->ptrBinder;
			delete ptrArrayStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void deleteLinkedStack(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			LinkedStack<int>* intLinkedStack = (LinkedStack<int>*)handle->ptrBinder;
			delete intLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			LinkedStack<long>* longLinkedStack = (LinkedStack<long>*)handle->ptrBinder;
			delete longLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			LinkedStack<UINT_PTR>* ptrLinkedStack = (LinkedStack<UINT_PTR>*)handle->ptrBinder;
			delete ptrLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void deleteConcurrentLinkedStack(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			LinkedStack<int>* intLinkedStack = (ConcurrentLinkedStack<int>*)handle->ptrBinder;
			delete intLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			LinkedStack<long>* longLinkedStack = (ConcurrentLinkedStack<long>*)handle->ptrBinder;
			delete longLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			LinkedStack<UINT_PTR>* ptrLinkedStack = (ConcurrentLinkedStack<UINT_PTR>*)handle->ptrBinder;
			delete ptrLinkedStack;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

void deleteArrayQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			ArrayQueue<int>* intArrayQueue = (ArrayQueue<int>*)handle->ptrBinder;
			delete intArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			ArrayQueue<long>* longArrayQueue = (ArrayQueue<long>*)handle->ptrBinder;
			delete longArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			ArrayQueue<UINT_PTR>* ptrArrayQueue = (ArrayQueue<UINT_PTR>*)handle->ptrBinder;
			delete ptrArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void deleteConcurrentArrayQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			ConcurrentArrayQueue<int>* intArrayQueue = (ConcurrentArrayQueue<int>*)handle->ptrBinder;
			delete intArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			ConcurrentArrayQueue<long>* longArrayQueue = (ConcurrentArrayQueue<long>*)handle->ptrBinder;
			delete longArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			ConcurrentArrayQueue<UINT_PTR>* ptrArrayQueue = (ConcurrentArrayQueue<UINT_PTR>*)handle->ptrBinder;
			delete ptrArrayQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void deleteLinkedQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			LinkedQueue<int>* intLinkedQueue = (LinkedQueue<int>*)handle->ptrBinder;
			delete intLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			LinkedQueue<long>* longLinkedQueue = (LinkedQueue<long>*)handle->ptrBinder;
			delete longLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			LinkedQueue<UINT_PTR>* ptrLinkedQueue = (LinkedQueue<UINT_PTR>*)handle->ptrBinder;
			delete ptrLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}
void deleteConcurrentLinkedQueue(DSHandle* handle) {
	switch(handle->eDataType) {
		case eDATATYPE_INTEGER :
		{
			ConcurrentLinkedQueue<int>* intLinkedQueue = (ConcurrentLinkedQueue<int>*)handle->ptrBinder;
			delete intLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_LONG :
		{
			ConcurrentLinkedQueue<long>* longLinkedQueue = (ConcurrentLinkedQueue<long>*)handle->ptrBinder;
			delete longLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		case eDATATYPE_PTR :
		{
			LinkedQueue<UINT_PTR>* ptrLinkedQueue = (ConcurrentLinkedQueue<UINT_PTR>*)handle->ptrBinder;
			delete ptrLinkedQueue;
			handle->ptrBinder = (UINT_PTR)NULL;
		}
		break;
		default :
			//no op.
		break;
	}

	handle->bValid = IS_NOT_NULL(handle->ptrBinder);
}

/////////////////////////////////////////////////////////////
//TYPE SPECIFIC : INTEGER STACK
/////////////////////////////////////////////////////////////
void setDefaultIntegerArrayStackHandle(DSHandle* a_phDS, int a_nSize, bool a_bConcurrent) {
	a_phDS->bValid = false;
	a_phDS->eDSType = a_bConcurrent ? eDSTYPE_CONCURRENT_ARRAY_STACK : eDSTYPE_ARRAY_STACK;
	a_phDS->eDataType = eDATATYPE_INTEGER;
	a_phDS->nMaxSize = a_nSize;
	a_phDS->ptrBinder = (UINT_PTR)NULL;
}

void setDefaultIntegerLinkedStackHandle(DSHandle* a_phDS, int a_nMaxSize, bool a_bConcurrent) {
	a_phDS->bValid = false;
	a_phDS->eDSType = a_bConcurrent ? eDSTYPE_CONCURRENT_LINKED_STACK : eDSTYPE_LINKED_STACK;
	a_phDS->eDataType = eDATATYPE_INTEGER;
	a_phDS->nMaxSize = a_nMaxSize;
	a_phDS->ptrBinder = (UINT_PTR)NULL;
}

void pushIntStack(DSHandle* a_hDS, int a_nData) {
	BaseStack<int>* ptrStack = bindIntStack(a_hDS);
	ptrStack->push(a_nData);
}

int popIntStack(DSHandle* a_hDS) {
	BaseStack<int>* ptrStack = bindIntStack(a_hDS);
	return ptrStack->pop();
}

bool canPushIntStack(DSHandle* a_hDS) {
	BaseStack<int>* ptrStack = bindIntStack(a_hDS);
	return ptrStack->canPush();
}

bool canPopIntStack(DSHandle* a_hDS) {
	BaseStack<int>* ptrStack = bindIntStack(a_hDS);
	return ptrStack->canPop();
}

int getDataCountIntStack(DSHandle* a_hDS) {
	BaseStack<int>* ptrStack = bindIntStack(a_hDS);
	return ptrStack->getDataCount();
}

BaseStack<int>* bindIntStack(DSHandle* a_hDS) {
	if(a_hDS->bValid == false) {
		throw DSNotInitializedException();
		
	}

	BaseStack<int>* ptrStack = NULL;

	switch(a_hDS->eDSType) {
		case eDSTYPE_ARRAY_STACK :
		case eDSTYPE_CONCURRENT_ARRAY_STACK :
			ptrStack = (BaseStack<int>*)a_hDS->ptrBinder;
			break;
		case eDSTYPE_LINKED_STACK :
		case eDSTYPE_CONCURRENT_LINKED_STACK :
			ptrStack = (BaseStack<int>*)a_hDS->ptrBinder;
			break;
		default :
			//no op.
			break;
	}

	if(ptrStack == NULL) {
		throw DSInvalidTypeException();
	}

	return ptrStack;
}

/////////////////////////////////////////////////////////////
//TYPE SPECIFIC : INTEGER Queue
/////////////////////////////////////////////////////////////
void setDefaultIntegerArrayQueueHandle(DSHandle* a_phDS, int a_nSize, bool a_bConcurrent) {
	a_phDS->bValid = false;
	a_phDS->eDSType = a_bConcurrent ? eDSTYPE_CONCURRENT_ARRAY_QUEUE : eDSTYPE_ARRAY_QUEUE;
	a_phDS->eDataType = eDATATYPE_INTEGER;
	a_phDS->nMaxSize = a_nSize;
	a_phDS->ptrBinder = (UINT_PTR)NULL;
}
void setDefaultIntegerLinkedQueueHandle(DSHandle* a_phDS, int a_nMaxSize, bool a_bConcurrent) {
	a_phDS->bValid = false;
	a_phDS->eDSType = a_bConcurrent ? eDSTYPE_CONCURRENT_LINKED_QUEUE : eDSTYPE_LINKED_QUEUE;
	a_phDS->eDataType = eDATATYPE_INTEGER;
	a_phDS->nMaxSize = a_nMaxSize;
	a_phDS->ptrBinder = (UINT_PTR)NULL;
}
void offerIntQueue(DSHandle *a_hDS, int a_nData) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	ptrQueue->offer(a_nData);
}
int pollIntQueue(DSHandle *a_hDS) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	return ptrQueue->poll();
}
int peekIntQueue(DSHandle *a_hDS) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	return ptrQueue->peek();
}
bool canOfferIntQueue(DSHandle *a_hDS) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	return ptrQueue->canOffer();
}
bool canPollIntQueue(DSHandle *a_hDS) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	return ptrQueue->canPoll();
}
int getDataCountIntQueue(DSHandle *a_hDS) {
	BaseQueue<int>* ptrQueue = bindIntQueue(a_hDS);
	return ptrQueue->getDataCount();
}

BaseQueue<int>* bindIntQueue(DSHandle* a_hDS) {
	if(a_hDS->bValid == false) {
		throw DSNotInitializedException();
	}

	BaseQueue<int>* ptrQueue = NULL;

	switch(a_hDS->eDSType) {
		case eDSTYPE_ARRAY_QUEUE :
		case eDSTYPE_CONCURRENT_ARRAY_QUEUE :
			ptrQueue = (BaseQueue<int>*)a_hDS->ptrBinder;
			break;
		case eDSTYPE_LINKED_QUEUE :
		case eDSTYPE_CONCURRENT_LINKED_QUEUE :
			ptrQueue = (BaseQueue<int>*)a_hDS->ptrBinder;
			break;
		default :
			//no op.
			break;
	}

	if(ptrQueue == NULL) {
		throw DSInvalidTypeException();
	}

	return ptrQueue;
}
